package com.drivers.wallet.controller;

import cn.hutool.core.lang.UUID;
import com.drivers.model.BaseEntity;
import com.drivers.model.R;
import com.drivers.model.wallet.DriversWallet;
import com.drivers.wallet.config.SimpleRedisLock;
import com.drivers.wallet.service.WalletService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.RedissonLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.concurrent.TimeUnit;

import static java.lang.Thread.sleep;

/**
 * @Author zhaomingshuo
 * @Date: 2024/08/23
 */

@RestController
@RequestMapping("/wallet")
@Slf4j
public class WalletController {

    @Autowired
    WalletService walletService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    RedissonClient redissonClient;



    @Autowired
    Redisson redisson;


    /**
     * 查询所有银行卡
     * @return
     */

    @RequestMapping("/walletfindAll/{userid}")
    public R walletfindAll(@PathVariable Integer userid){
        List<DriversWallet> driversWallet=walletService.walletfindAll(userid);
        return  R.ok(driversWallet);
    }

    /**
     *
     * 逻辑删除银行卡
     * @param id
     * @return
     */
    @RequestMapping("/deletewallet/{id}")
    public R deletewallet(@PathVariable Integer id){
        return R.ok(walletService.deletewallet(id));
    }

    /**
     *
     * 添加新的银行卡
     * @param driversWallet
     * @return
     */

    @RequestMapping("/walletadd")
    public R walletadd(@RequestBody DriversWallet driversWallet){
        return R.ok(walletService.walletadd(driversWallet));
    }

    /**
     *
     *修改用户的银行卡免密状态
     * 关闭免密支付 免密状态(已开通:1;去开通:0)
     * @param id
     * @return
     */
    @RequestMapping("/updateFreeStatus/{id}")
    public R updateFreeStatus(@PathVariable Integer id){
        return R.ok(walletService.updateFreeStatus(id));
    }

    /**
     *
     * 修改用户的银行卡优先级状态
     * @param id
     * @return
     */
    @RequestMapping("/precedenceStatus/{id}")
    public R precedenceStatus(@PathVariable Integer id){
        return R.ok(walletService.precedenceStatus(id));
    }

    /**
     *
     * 开通免密支付接口
     * @param id
     * @return
     */
    @RequestMapping("/openSecretfree/{id}")
    public R openSecretfree(@PathVariable Integer id){
        return R.ok(walletService.openSecretfree(id));
    }

    /**
     *
     * 根据id查询银行卡1
     * @param id
     * @return
     */
    @RequestMapping("/DriversWalletbyid/{id}")
    public R DriversWalletbyid(@PathVariable Integer id){
        String lockkey="lock:produce:101";
        redisTemplate.opsForValue().set("lock:produce",10);
        stringRedisTemplate.delete(lockkey);
        return R.ok(walletService.DriversWalletbyid(id));

    }


    @Autowired
    RedisTemplate redisTemplate;



    /**
     * TODO 第一种方式使用Redis实现 测试分布式锁
     * @return
     */
    @RequestMapping("Spring_cloud")
    public R Spring_cloud(){
        String lockkey="lock:produce:101";
//        只能有一个获取到锁
//        TODO 为了防止数据库宕机 给锁加一个过期时间  就算宕机过了10秒也可以继续使用
//         设置过期时间一定要在一行代码，保证一致性   如果写两行代码如果redis挂了  就会出现死锁


        /*
        TODO 锁的失效时间要大于线程执行的时间
        避免锁失效：
        用uuid生成随机数 来保证删除的是自己加的锁
         */

        String clientId = UUID.randomUUID().toString();
        System.out.println(clientId);
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockkey, clientId, 10, TimeUnit.SECONDS);
//        有人拿到就是直接返回
        if (!result){
            return R.ok("线程使用中");
        }

//        RLock redissonLock = redisson.getLock(lockkey);
//        redissonLock.lock(10, TimeUnit.SECONDS);

        try {


            int sumber = (int) redisTemplate.opsForValue().get("lock:produce");
            if (sumber>0){
                sumber=sumber-1;
                redisTemplate.opsForValue().set("lock:produce",sumber);
                System.out.println("抢购成功!数量为: "+sumber);
            }else {
                System.out.println("抢购失败!数量为: "+sumber);
            }

//
        } finally {
//            redissonLock.unlock();
//            用uuid识别释放是自己加的锁如果是就可以释放

            System.out.println(stringRedisTemplate.opsForValue().get(lockkey));
            if (clientId.equals(stringRedisTemplate.opsForValue().get(lockkey))){
//          如果有异常就执行删除 释放掉锁  如果不释放锁的话 后面的人在调用接口的时候就无法使用  就会出现死锁
//                如果在这里卡了 整好锁正好过期了 在删除的时候就会删除别人加的锁  增加过期时间
                stringRedisTemplate.delete(lockkey);
            }
        }
        return R.ok("Spring_cloud");
    }



    /**
     * TODO 第二种方式  测试分布式锁
     * @return
     */
    @RequestMapping("Spring_clouds")
    public R Spring_clouds()  {
        String lockkey="lock:produce:101";

//        使用之前必须把导入

        SimpleRedisLock redisLock = new SimpleRedisLock(lockkey, stringRedisTemplate);

//        RLock redisLock = redissonClient.getLock(lockkey);
        boolean isLock = redisLock.tryLock(600);

        // 判断
        if (!isLock) {
            // 获取锁失败，直接返回失败或者重试
            log.error("不允许重复下单！");
            return R.error("不允许重复下单！");
        }
//        RLock redissonLock = redisson.getLock(lockkey);
//        redissonLock.tryLock();

        try {
            int sumber = (Integer) redisTemplate.opsForValue().get("lock:produce");
            if (sumber>0){
                sumber=sumber-1;
                redisTemplate.opsForValue().set("lock:produce",sumber);
                System.out.println("抢购成功!数量为: "+sumber);
            }else {
                System.out.println("抢购失败!数量为: "+sumber);
            }
        }finally {
//            释放锁
//            redissonLock.unlock();
//            if (redisLock.isHeldByCurrentThread()){
                redisLock.unlock();
//            }


        }
        return R.ok("Spring_cloud");
    }

    /**
     * TODO 第三种方式使用redisson方式 测试分布式锁
     * @return
     */
    @RequestMapping("Spring_cloudss")
    public R Spring_cloudss() throws InterruptedException {
        String lockkey="lock:produce:101";

//        使用之前必须把导入

        RLock lock = redissonClient.getLock("anyLock");
        boolean isLock = lock.tryLock(1, 10, TimeUnit.SECONDS);
        // 判断
        if (!isLock) {
            // 获取锁失败，直接返回失败或者重试
            log.error("不允许重复下单！");
            return R.error("不允许重复下单！");
        }
        try {
            int sumber = (Integer) redisTemplate.opsForValue().get("lock:produce");
            if (sumber>0){
                sumber=sumber-1;
                redisTemplate.opsForValue().set("lock:produce",sumber);
                System.out.println("抢购成功!数量为: "+sumber);
            }else {
                System.out.println("抢购失败!数量为: "+sumber);
            }
        }finally {
//            释放锁
            lock.unlock();
        }
        return R.ok("Spring_cloud");
    }






}
